﻿using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Animation;
using KlearTweet.Client.Model;

namespace KlearTweet.Client.DataContainers
{
	public partial class ListItem // TODO: From Silverlight2Beta1Controls
	{
        private IEntity _entity;

        public IEntity Entity // TODO: Data-binding
		{
			get { return _entity; }
			set
            {
                if (_entity == value)
                    return;
                _entity = value;
                EntityView.Child = ParentListView.EntityViewProvider(Entity);
			}
        }

        public void Clear()
        {
            //_entity = null;
            IsSelected = false;
            ParentListView = null;
        }



		/// <summary>
        /// Gets or sets a value that indicates whether a ListItem is selected. 
        /// </summary>
        public bool IsSelected
        { 
            get { return (bool)GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        } 
 
        /// <summary>
        /// Identifies the IsSelected dependency property. 
        /// </summary>
        public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(
            "IsSelected", typeof(bool), typeof(ListItem), new PropertyMetadata(OnIsSelectedChanged));

        private bool _isMousePressed;
		private bool _isMouseOver;
		/// <summary> 
        /// Gets a value that indicates whether the mouse pointer is located over this element. 
        /// </summary>
        public bool IsMouseOver
		{
			get { return _isMouseOver; }
			private set
			{
				_isMouseOver = value;
				ChangeVisualState();
			}
		}

		/// <summary> 
        /// Identifies the parent ListView.
        /// </summary> 
		internal ListView ParentListView { get; set; }
/*
        /// <summary> 
        /// Identifies the root visual element from the template.
        /// </summary>
        private FrameworkElement ElementRoot { get; set; } 
        private const string ElementRootName = "RootElement"; 

        /// <summary> 
        /// Identifies the focus visual element from the template.
        /// </summary>
        private FrameworkElement ElementFocusVisual { get; set; } 
        private const string ElementFocusVisualName = "FocusVisualElement";
*/
        /// <summary> 
        /// Identifies the normal state. 
		/// </summary>
		private Storyboard StateNormal { get; set; }
        private const string StateNormalName = "Normal State"; 
 
        /// <summary>
        /// Identifies the selected state (with fallback). 
        /// </summary>
        private Storyboard StateSelected
        { 
            get { return _stateSelected ?? StateSelectedFocused; }
            set { _stateSelected = value; }
        } 
        private Storyboard _stateSelected; 
        private const string StateSelectedName = "Unfocused Selected State";
 
        /// <summary>
        /// Identifies the selected+focused state (with fallback).
        /// </summary> 
        private Storyboard StateSelectedFocused
        {
            get { return _stateSelectedFocused ?? StateNormal; } 
            set { _stateSelectedFocused = value; } 
        }
        private Storyboard _stateSelectedFocused; 
        private const string StateSelectedFocusedName = "Normal Selected State";

        /// <summary> 
        /// Identifies the normal+mouse state (with fallback).
        /// </summary>
        private Storyboard StateMouseOver 
        { 
            get { return _stateMouseOver ?? StateNormal; }
            set { _stateMouseOver = value; } 
        }
        private Storyboard _stateMouseOver;
        private const string StateMouseOverName = "MouseOver State"; 

        /// <summary>
        /// Identifies the selected+mouse state (with fallback). 
        /// </summary> 
        private Storyboard StateMouseOverSelected
        { 
            get { return _stateMouseOverSelected ?? StateMouseOverSelectedFocused; }
            set { _stateMouseOverSelected = value; }
        } 
        private Storyboard _stateMouseOverSelected;
        private const string StateMouseOverSelectedName = "MouseOver Unfocused Selected State";
 
        /// <summary> 
        /// Identifies the selected+mouse+focused state (with fallback).
        /// </summary> 
        private Storyboard StateMouseOverSelectedFocused
        {
            get { return _stateMouseOverSelectedFocused ?? StateSelectedFocused; } 
            set { _stateMouseOverSelectedFocused = value; }
        }
        private Storyboard _stateMouseOverSelectedFocused;
		private const string StateMouseOverSelectedFocusedName = "MouseOver Selected State";

        /// <summary> 
        /// Identifies the current state.
        /// </summary>
        private Storyboard CurrentState { get; set; } 

        /// <summary>
        /// Initializes a new instance of the ListItem class. 
        /// </summary> 
		public ListItem()
		{
			InitializeComponent();

        	var ElementRoot = RootElement;
			StateNormal = ElementRoot.Resources[StateNormalName] as Storyboard;
			StateSelected = ElementRoot.Resources[StateSelectedName] as Storyboard;
			StateSelectedFocused = ElementRoot.Resources[StateSelectedFocusedName] as Storyboard;
			StateMouseOver = ElementRoot.Resources[StateMouseOverName] as Storyboard;
			StateMouseOverSelected = ElementRoot.Resources[StateMouseOverSelectedName] as Storyboard;
			StateMouseOverSelectedFocused = ElementRoot.Resources[StateMouseOverSelectedFocusedName] as Storyboard;

#if WPF
            KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Once);
            KeyboardNavigation.SetTabNavigation(this, KeyboardNavigationMode.Local); 
#else
            // DirectionalNavigation not supported by Silverlight
            TabNavigation = KeyboardNavigationMode.Local; 
#endif 
            IsTabStop = true;
            MouseLeftButtonDown += ((sender, e) => OnMouseLeftButtonDown(e)); 
            MouseEnter += delegate { IsMouseOver = true; };
			MouseLeave += delegate { IsMouseOver = false; };
            /*GotFocus += ((sender, e) => OnGotFocus(e)); 
            LostFocus += ((sender, e) => OnLostFocus(e));*/
        }
 /*
#if WPF
        public override void OnApplyTemplate()
#else 
        /// <summary> 
        /// Invoked whenever application code or internal processes call
        /// ApplyTemplate. 
        /// </summary>
        protected override void OnApplyTemplate()
#endif 
        {
            base.OnApplyTemplate();
 
            ElementRoot = GetTemplateChild(ElementRootName) as FrameworkElement; 
            if (null != ElementRoot)
            { 
                StateNormal = ElementRoot.Resources[StateNormalName] as Storyboard;
                StateSelected = ElementRoot.Resources[StateSelectedName] as Storyboard;
                StateSelectedFocused = ElementRoot.Resources[StateSelectedFocusedName] as Storyboard; 
                StateMouseOver = ElementRoot.Resources[StateMouseOverName] as Storyboard;
                StateMouseOverSelected = ElementRoot.Resources[StateMouseOverSelectedName] as Storyboard;
                StateMouseOverSelectedFocused = ElementRoot.Resources[StateMouseOverSelectedFocusedName] as Storyboard; 
            } 
            ElementFocusVisual = GetTemplateChild(ElementFocusVisualName) as FrameworkElement;
        } */


        /// <summary>
        /// Called when the user presses the left mouse button over the ListItem. 
        /// </summary>
        /// <param name="e">The event data.</param>
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) 
        {
            base.OnMouseLeftButtonDown(e);
            _isMousePressed = true;
            if (!e.Handled)
            { 
                e.Handled = true;
                if (Focus())
                {
                    if (null != ParentListView)
                    {
                        ParentListView.NotifyListItemPressed(this); 
                    } 
                }
            }
        }

        /*private System.DateTime _dateTimeLimitForDoubleClick; // TODO: Old implementation. Remove?

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);
            var clicked = _isMousePressed;
            var secondTime = System.DateTime.Now < _dateTimeLimitForDoubleClick;

            _isMousePressed = false;
            if (!e.Handled)
            {
                e.Handled = true;
                if (clicked)
                {
                    _dateTimeLimitForDoubleClick = secondTime ? System.DateTime.MinValue // User must start over
                        : System.DateTime.Now.AddMilliseconds(200);
                    if (secondTime)
                        ParentListView.NotifyListItemDoubleClicked(this);
                    else
                        ParentListView.NotifyListItemClicked(this);
                }
            }
        }*/

        private System.Windows.Threading.DispatcherTimer _clickTimer;
        private bool _timerWasJustEnabled;

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);
            var clicked = _isMousePressed;
            _isMousePressed = false;
            if (!e.Handled)
            {
                e.Handled = true;
                if (!clicked) // The idea of this implementation is: When the user clicks, wait to see if it is a double-click
                    return;
                if (_clickTimer == null) // Init
                {
                    _clickTimer = new System.Windows.Threading.DispatcherTimer
                    { Interval = new System.TimeSpan(0, 0, 0, 0, 200) }; // TODO: Tweak - What is the standard double-click delay?
                    _clickTimer.Tick += delegate
                    {
                        if (_timerWasJustEnabled) // Ignore
                        {
                            _timerWasJustEnabled = false;
                            return;
                        }
                        _clickTimer.Stop();
                        if (ParentListView != null)
                            ParentListView.NotifyListItemClicked(this);
                    };
                }
                if (_clickTimer.IsEnabled) // Second click
                {
                    _clickTimer.Stop();
                    if (ParentListView != null)
                        ParentListView.NotifyListItemDoubleClicked(this);
                }
                else
                {
                    _timerWasJustEnabled = true;
                    _clickTimer.Start(); // First click, wait to generate event
                }
            }
        }

        protected override void OnMouseMove(MouseEventArgs e) // Because Panning inside an Image should cancel Click; Otherwise, it will go from Thumbnail to Preview. And that's how other programs behave
        {
            base.OnMouseMove(e);
            _isMousePressed = false;
        }



        /// <summary>
        /// Called when the control got focus. 
        /// </summary> 
        /// <param name="e">The event data.</param>
        protected override void OnGotFocus(RoutedEventArgs e)
        {
            base.OnGotFocus(e);
			var ElementFocusVisual = FocusVisualElement;
            if (null != ElementFocusVisual)
            { 
                ElementFocusVisual.Visibility = Visibility.Visible;
            }
            if (null != ParentListView) 
            { 
                ParentListView.NotifyListItemGotFocus(this);
            }
        }

        /// <summary> 
        /// Called when the control lost focus.
        /// </summary>
        /// <param name="e">The event data.</param> 
        protected override void OnLostFocus(RoutedEventArgs e)
        {
            base.OnLostFocus(e);
			var ElementFocusVisual = FocusVisualElement;
            if (null != ElementFocusVisual) 
            {
                ElementFocusVisual.Visibility = Visibility.Collapsed;
            } 
            if (null != ParentListView)
            {
                ParentListView.NotifyListItemLostFocus(this);
			}
        }
 
        /// <summary>
        /// Implements the IsSelectedProperty PropertyChangedCallback.
        /// </summary> 
        /// <param name="d">The DependencyObject for which the property changed.</param>
        /// <param name="e">Provides data for DependencyPropertyChangedEventArgs.</param>
        private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        { 
            var listItem = d as ListItem;
            System.Diagnostics.Debug.Assert(null != listItem); 
            System.Diagnostics.Debug.Assert(typeof(bool).IsInstanceOfType(e.OldValue));
            System.Diagnostics.Debug.Assert(typeof(bool).IsInstanceOfType(e.NewValue));
            listItem.ChangeVisualState();
        }

        /// <summary> 
        /// Changes the visual state by playing the appropriate Storyboard 
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "An invalid Storyboard or playing a Storyboard at the wrong time throws System.Exception.")] 
        internal void ChangeVisualState()
        {
            if (null != ParentListView) 
            {
                Storyboard newState;
                if (IsSelected) 
                { 
                    newState = (ListView.GetIsSelectionActive(ParentListView) ?
                        (IsMouseOver ? StateMouseOverSelectedFocused : StateSelectedFocused) :
                        (IsMouseOver ? StateMouseOverSelected : StateSelected));
                }
                else 
                {
                    newState = (IsMouseOver ? StateMouseOver : StateNormal);
                }

                if ((null != newState) && (CurrentState != newState)) 
                {
                    // Begin the new state transition 
                    try
                    {
                        newState.Begin();
                        // Update the current state
                        var previousState = CurrentState;
                        CurrentState = newState;
                        // Stop the old state transition (per Silverlight convention)
                        if (null != previousState)
                        {
                            previousState.Stop(); 
                        }
                    }
// ReSharper disable EmptyGeneralCatchClause
                    catch 
// ReSharper restore EmptyGeneralCatchClause
                    {
                        // Silverlight Storyboard.Begin must always be wrapped in try/catch
                    } 
                } 
            }
        }
	}
}
